package es.ucm.fdi.isbc.viviendas.funciones_similitud;

import es.ucm.fdi.isbc.viviendas.representacion.Coordenada;
import jcolibri.method.retrieve.NNretrieval.similarity.LocalSimilarityFunction;

public class SimCoordenadas implements LocalSimilarityFunction{

	double _interval;

	/**
	 * Constructor.
	 */
	public SimCoordenadas(double interval) {
		_interval = interval;
	}

	public double compute(Object o1, Object o2) throws jcolibri.exception.NoApplicableSimilarityFunctionException{
		//Si los dos objetos son null se devuelve 0
		if ((o1 == null) || (o2 == null))
			return 0;
		if (!(o1 instanceof Coordenada))
			throw new jcolibri.exception.NoApplicableSimilarityFunctionException(this.getClass(), o1.getClass());
		if (!(o2 instanceof Coordenada))
			throw new jcolibri.exception.NoApplicableSimilarityFunctionException(this.getClass(), o2.getClass());

		//Pasamos los objetos a coordenadas
		Coordenada c1= (Coordenada) o1;
		Coordenada c2= (Coordenada) o2;
		//Obtenemos la longitud y la latitud de las coordenadas
		double lon1 = c1.getLongitud();
		double lat1 = c1.getLatitud();
		double lon2 = c2.getLongitud();
		double lat2 = c2.getLatitud();
		
		//Calculamos la diferencia con _interval
		double gradToRad = 0.01745329;
		double radToGrad = 57.29577951; 
		double difLong = lon1 - lon2;
		//Calculamos el valor en radianes
		double value = (Math.sin(lat1*gradToRad)*Math.sin(lat2*gradToRad))
			+(Math.cos(lat1*gradToRad)* Math.cos(lat2*gradToRad)
			*Math.cos(difLong*gradToRad));
		//Transformamos el valor a grados
		double dd= Math.acos(value)*radToGrad;
		//Pasamos los grados a kilometros
		double dist= dd*111.302;
		//Calculamos la similitud con _interval
		double res=1.0 - (dist / _interval);
		//Si res es mayor que 0 devuelve res, si no 0
		return res > 0 ? res : 0.0;

	}

	public boolean isApplicable(Object o1, Object o2)
	{
		//Comprobamos que los objetos son Coordenada o null
		if((o1==null)&&(o2==null))
			return true;
		else if(o1==null)
			return o2 instanceof Coordenada;
		else if(o2==null)
			return o1 instanceof Coordenada;
		else
			return (o1 instanceof Coordenada)&&(o2 instanceof Coordenada);
	}

}
